package com.jdd.fintech.morse.plugin;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.jdd.fintech.morse.plugin.enums.BizErrorCodeEnum;
import com.jdd.fintech.morse.plugin.enums.BooleanEnum;
import com.jdd.fintech.morse.plugin.enums.CustomVersionEnum;
import com.jdd.fintech.morse.plugin.plugconfig.MorsePlugValueConfig;
import com.jdd.fintech.morse.plugin.plugconfig.MorsePlugValueTokenConfig;
import com.jdd.fintech.morse.plugin.util.PluginDateUtils;
import com.jddglobal.filter.Filter;
import com.jddglobal.filter.data.Context;
import com.jddglobal.filter.data.RemoteCommand;
import com.jddglobal.filter.data.Resource;
import com.jddglobal.filter.support.exception.FilterException;
import com.jddglobal.phevos.gateway.resources.ResourceCapability;
import org.apache.commons.httpclient.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.jdd.fintech.morse.plugin.constans.OpenApiConstans.*;
import static com.jdd.fintech.morse.plugin.util.HttpClientUtil.*;
import static com.jdd.fintech.morse.plugin.util.PluginDateUtils.getDateTimeDifference;


/**
 * @description: Morse 获取服务器Token令牌插件
 * @date: 2022/3/25 15:22
 * @author: fengcheng
 **/
public class MoresOpenApiTokenFilter implements Filter {

    public static Map<String, JSONObject> globelTokenMap = Maps.newHashMap();

    /**
     * 日志输出对象
     */
    private static final Logger log = LoggerFactory.getLogger(MoresOpenApiTokenFilter.class);

    @Override
    public <R, S> Resource<Object> filter(Context<R, S> context, List<ConfigurationValue> dynamic) throws FilterException {
        try {
            log.info("MoresOpenApiTokenFilter.filter.开始执行Morse-OpenApi-Token令牌插件======>开始");
            //1.获取插件值中的配置
            if (CollectionUtils.isEmpty(dynamic)) {
                throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_2.getCode(), BizErrorCodeEnum.FAILURE_2.getDesc()));
            }
            CustomVersionEnum customVersion = null;
            MorsePlugValueConfig plugValueConfig = null;
            for (ConfigurationValue obj : dynamic) {
                String settingValue = obj.getSettingValue();
                if(StringUtils.isBlank(settingValue)){
                    continue;
                }
                JSONObject json = JSONObject.parseObject(settingValue);
                customVersion = CustomVersionEnum.valueOf(json.getString(CUSTOMVERSION_KEY));
                //获取插件值配置对象
                plugValueConfig = new MorsePlugValueConfig(customVersion, BooleanEnum.valueOf(json.getString(REMOTETOKEN_KEY)),
                                                           JSONObject.parseObject(json.getString(TOKENCONFIG_KEY), MorsePlugValueTokenConfig.class));
            }
            if(ObjectUtils.isEmpty(plugValueConfig)){
                log.error("MoresOpenApiTokenFilter.filter.获取远程访问令牌|插件链未配置插件值，不进行后续处理");
                return Resource.OK();
            }
            //判断哪个机构需要调用远程服务进行获取token
            if(isCallRemoteInterfaceGetToken(customVersion)){
                //获取远程访问令牌
                String remoteAccessToken = getRemoteAccessToken(plugValueConfig);
                if(StringUtils.isNotBlank(remoteAccessToken)){
                    RemoteCommand remoteCommand = context.getRemoteCommand();
                    RemoteCommand.RemoteDefinition definition = remoteCommand.getDefinition();
                    String rpcType = definition.getRpcType();
                    //后端服务类型是 "HTTP" 类型才进行此操作
                    if(HTTP_KEY.equals(rpcType)){
                        String uri = definition.getUri();
                        String newUri = uri + "?access_token=" + remoteAccessToken + "&request_id=" + PluginDateUtils.parseDate2Long(new Date());
                        definition.setUri(newUri);
                    }
                } else {
                    log.error("MoresOpenApiTokenFilter.filter.开始执行Morse-OpenApi-Token令牌插件.获取令牌返回为空");
                }
            }
            log.info("MoresOpenApiTokenFilter.filter.开始执行Morse-OpenApi-Token令牌插件======>结束");
        } catch (Exception e) {
            log.error("MoresOpenApiTokenFilter.filter.获取远程访问令牌|发生异常| 异常信息：{}", e.getMessage(), e);
            throw new FilterException(new ResourceCapability.AutoDefineResource(BizErrorCodeEnum.FAILURE_7.getCode(), BizErrorCodeEnum.FAILURE_7.getDesc()));
        }
        return Resource.OK();
    }

    /**
     * 判断哪个机构需要调用远程服务进行获取token
     * 现阶段 平安惠普，才需要进行调用远程接口获取Token
     * @return
     */
    public static boolean isCallRemoteInterfaceGetToken(CustomVersionEnum customVersion){
        if(CustomVersionEnum.PAPH.getCode().equals(customVersion.getCode())){
            return true;
        }
        return false;
    }

    /**
     * 获取远程访问令牌
     * @param plugValueConfig
     * @throws FilterException
     */
    public String getRemoteAccessToken(MorsePlugValueConfig plugValueConfig) throws Exception {
        log.info("MoresOpenApiTokenFilter.getRemoteAccessToken.开始获取远程访问令牌======>开始");
        String accessToken = "";
        JSONObject jsonObject = new JSONObject();
        if (BooleanEnum.YES.getCode().equals(plugValueConfig.getRemoteToken().getCode())) {
            MorsePlugValueTokenConfig tokenConfig = plugValueConfig.getTokenConfig();
            String url = tokenConfig.getRequestAddress();
            String requestWay = tokenConfig.getRequestWay();
            String jsonStr = tokenConfig.getRequestParameter();
            JSONObject jsonObjPara = JSONObject.parseObject(jsonStr);
            String clientId = jsonObjPara.getString(CLIENT_ID_KEY);

            //校验缓存中是否存在该应用ID的数据
            JSONObject globelJsonObj = globelTokenMap.get(clientId);
            if(!ObjectUtils.isEmpty(globelJsonObj)){
                String time = globelJsonObj.getString("time");
                //加一个小时，到达token失效具体时间
                Date date = DateUtils.addMinutes(PluginDateUtils.parseStr2Date(time), 60);
                //通过token失效和当前时间进行比较，如果小于30分钟，则重新获取token，并记录到内存中
                long mitime = 30L;
                //如果获取的时间差小于等于30分钟，就需要重新发送请求获取Token
                if(mitime <= getDateTimeDifference(PluginDateUtils.parseDate2Str(date))){
                    //需要重新发起获取token请求
                    log.info("Token过期时间已经过半，需要重新发起获取Token请求");
                    jsonObject = startGetRemoteAccessToken(url, jsonStr, clientId, requestWay);
                } else {
                    jsonObject = JSONObject.parseObject(globelJsonObj.getString(DATA_KEY));
                }
            } else {
                jsonObject = startGetRemoteAccessToken(url, jsonStr, clientId, requestWay);
            }
        } else {
            log.warn("MoresOpenApiTokenFilter.getRemoteAccessToken.此请求不需要获取远, 插件链中：是否获取远程token配置值为：NO");
            return accessToken;
        }
        if(!ObjectUtils.isEmpty(jsonObject) && "0".equals(jsonObject.getString(RET_KEY))){
            accessToken = jsonObject.getString(ACCESS_TOKEN_KEY);
        }
        log.info("MoresOpenApiTokenFilter.getRemoteAccessToken.开始获取远程访问令牌======>结束");
        return accessToken;
    }

    /**
     * 开始调用远程服务，获取访问令牌（Token）
     * @param url
     * @param jsonStr
     * @param clientId
     * @param requestWay
     * @return
     * @throws Exception
     */
    public JSONObject startGetRemoteAccessToken(String url, String jsonStr, String clientId, String requestWay) throws Exception {
        log.info("MoresOpenApiTokenFilter.startGetRemoteAccessToken.开始调用远程服务，获取访问令牌（Token）======>开始");
        JSONObject jsonObj = null;
        String tokenResult = "";
        if(POST_KEY.equals(requestWay)){
            log.info("MoresOpenApiTokenFilter.startGetRemoteAccessToken.开始进行post调用");
            tokenResult = sendPost(url, jsonStr,  URL_PARAM_CHARSET_UTF8, CONTENT_TYPE);
        } else {
            log.info("MoresOpenApiTokenFilter.startGetRemoteAccessToken.开始进行get调用");
            Map<String, String> map = JSONObject.parseObject(jsonStr, Map.class);
            tokenResult = sendGet(url, map,  URL_PARAM_CHARSET_UTF8);
        }
        if(!ObjectUtils.isEmpty(tokenResult)){
            JSONObject jsonObject = JSONObject.parseObject(tokenResult);
//            String expiresIn = jsonObject.getString(EXPIRES_IN);
            //如果远程接口没有返回Token加入缓存的时间，则将返回来的数据结构，自行加入一个当前时间为加入缓存的时间
            jsonObject.put("time", DateUtil.formatDate(new Date(), PluginDateUtils.str_yyyy_MM_dd_HH_mm_ss));
            globelTokenMap.put(clientId, jsonObject);
            jsonObj = JSONObject.parseObject(jsonObject.getString(DATA_KEY));
        } else {
            log.warn("MoresOpenApiTokenFilter.startGetRemoteAccessToken.获取远程Token服务调用，返回结果为null");
        }
        log.error("MoresOpenApiTokenFilter.startGetRemoteAccessToken.开始调用远程服务，获取访问令牌（Token）======>结束");
        return jsonObj;
    }

}
